/*
  spr-sdk: Statistical Pattern Recognition SDK
  Copyright (C) 2010 Marco Ambu

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _PR_PATTERN_H
#define	_PR_PATTERN_H

#include "util/Real.h"
#include <vector>

namespace util {
  class Matrix;
} // namespace util

namespace pr {

class Pattern
{
public:
  class Operation
  {
  public:
    virtual ~Operation() {}
    virtual void operator()(Pattern& pattern) = 0;
  };

public:
  Pattern() {}
  Pattern(std::size_t featureCount);
  Pattern(const std::vector<util::Real>& values);
  template <typename Number>
  Pattern(const std::vector<Number>& values);

  std::size_t featureCount() const;

  util::Real getFeature(std::size_t i) const;
  void setFeature(std::size_t i, util::Real value);

  util::Real operator[](std::size_t i) const;
  util::Real& operator[](std::size_t i);

  util::Real min() const;
  util::Real max() const;
  void maxpos(util::Real& max, std::size_t& pos) const; // Max and max position
  util::Real mean() const;
  util::Real variance() const;
  void meanAndVariance(util::Real& meanValue, util::Real& variance);
  util::Real median() const;

  util::Real normInfinite() const;          // Norm infinite of std::vector
  util::Real norm1() const;                 // Norm 1 of std::vector
  util::Real norm2() const;                 // Norm 2 of std::vector

  Pattern& normalizeInfinite();       // Normalization -> Scaling to normInfinite(std::vector)=1
  Pattern& normalize2();              // Normalization -> Scaling to norm2(std::vector)=1
  Pattern& normalizeByMaxRange();
  Pattern& normalizeGauss();

  Pattern& sort(bool reverse = false);

  Pattern& operator+=(const Pattern& pattern);
  Pattern& operator-=(const Pattern& pattern);

  Pattern& operator+=(util::Real value);
  Pattern& operator-=(util::Real value);
  Pattern& operator*=(util::Real value);
  Pattern& operator/=(util::Real value);
  Pattern& operator^=(util::Real value);

  util::Real euclideanDistance(const Pattern& pattern) const;
  util::Real weightedEuclideanDistance(const Pattern& pattern, const std::vector<util::Real>& weight) const;
  util::Real cityblockDistance(const Pattern& pattern) const;
  util::Real mahalanobisDistance(const Pattern& pattern, const std::vector<util::Real>& weight) const;

  util::Real scalarProduct(const Pattern& pattern) const;
//
//  // Product component by component
//  pvector product(std::vector<util::Real>& v) const;
//  // This std::vector * v_Transposed
//  //squarematrix matrixproduct(std::vector<Real>& v);
//  // this * this_Transposed
//  util::smatrix selfproduct();
  // this * this_Transposed
  void selfProduct(util::Matrix& product);

  // da deprecare
  Pattern& project(const std::vector<Pattern>& vp);
  // ok
  Pattern projection(const std::vector<Pattern>& vp) const;

private:
  typedef std::vector<util::Real>::const_iterator const_iterator;
  typedef std::vector<util::Real>::iterator iterator;

private:
  std::vector<util::Real> pattern_;
};

Pattern operator+(const Pattern& left, const Pattern& right);
Pattern operator-(const Pattern& left, const Pattern& right);
Pattern operator+(const Pattern& left, util::Real value);
Pattern operator-(const Pattern& left, util::Real value);
Pattern operator*(const Pattern& left, util::Real value);
Pattern operator/(const Pattern& left, util::Real value);
Pattern operator^(const Pattern& left, util::Real value);

template <typename Number>
Pattern::Pattern(const std::vector<Number>& values)
{
  typedef typename std::vector<Number>::const_iterator iter;
  for (iter it = values.begin(); it != values.end(); ++it)
  {
    pattern_.push_back(*it);
  }
}

} // namespace pr

// import specialization for Formatter::toStream template method
#include "pr/PatternFormatter.h"

#endif	// _PR_PATTERN_H
